const sm2 = require('sm-crypto').sm2;
const sm3 = require('sm-crypto').sm3;
const sm4 = require('sm-crypto').sm4;
const fs = require("fs");
const compressing = require('compressing');
const mimeTypes = {
    '323':    'text/h323',
    'acx':    'application/internet-property-stream',
    'ai':     'application/postscript',
    'aif':    'audio/x-aiff',
    'aifc':   'audio/x-aiff',
    'aiff':   'audio/x-aiff',
    'asf':    'video/x-ms-asf',
    'asr':    'video/x-ms-asf',
    'asx':    'video/x-ms-asf',
    'au':     'audio/basic',
    'avi':    'video/x-msvideo',
    'axs':    'application/olescript',
    'bas':    'text/plain',
    'bcpio':  'application/x-bcpio',
    'bin':    'application/octet-stream',
    'bmp':    'image/bmp',
    'c':      'text/plain',
    'cat':    'application/vnd.ms-pkiseccat',
    'cdf':    'application/x-cdf',
    'cer':    'application/x-x509-ca-cert',
    'class':  'application/octet-stream',
    'clp':    'application/x-msclip',
    'cmx':    'image/x-cmx',
    'cod':    'image/cis-cod',
    'cpio':   'application/x-cpio',
    'crd':    'application/x-mscardfile',
    'crl':    'application/pkix-crl',
    'crt':    'application/x-x509-ca-cert',
    'csh':    'application/x-csh',
    'css':    'text/css',
    'dcr':    'application/x-director',
    'der':    'application/x-x509-ca-cert',
    'dir':    'application/x-director',
    'dll':    'application/x-msdownload',
    'dms':    'application/octet-stream',
    'doc':    'application/msword',
    'docx':    'application/msword',
    'dot':    'application/msword',
    'dvi':    'application/x-dvi',
    'dxr':    'application/x-director',
    'eps':    'application/postscript',
    'etx':    'text/x-setext',
    'evy':    'application/envoy',
    'exe':    'application/octet-stream',
    'fif':    'application/fractals',
    'flr':    'x-world/x-vrml',
    'gif':    'image/gif',
    'gtar':   'application/x-gtar',
    'gz':     'application/x-gzip',
    'h':      'text/plain',
    'hdf':    'application/x-hdf',
    'hlp':    'application/winhlp',
    'hqx':    'application/mac-binhex40',
    'hta':    'application/hta',
    'htc':    'text/x-component',
    'htm':    'text/html',
    'html':   'text/html',
    'htt':    'text/webviewhtml',
    'ico':    'image/x-icon',
    'ief':    'image/ief',
    'iii':    'application/x-iphone',
    'ins':    'application/x-internet-signup',
    'isp':    'application/x-internet-signup',
    'jfif':   'image/pipeg',
    'jpe':    'image/jpeg',
    'jpeg':   'image/jpeg',
    'jpg':    'image/jpeg',
    'js':     'application/x-javascript',
    'latex':  'application/x-latex',
    'lha':    'application/octet-stream',
    'lsf':    'video/x-la-asf',
    'lsx':    'video/x-la-asf',
    'lzh':    'application/octet-stream',
    'm13':    'application/x-msmediaview',
    'm14':    'application/x-msmediaview',
    'm3u':    'audio/x-mpegurl',
    'man':    'application/x-troff-man',
    'mdb':    'application/x-msaccess',
    'me':     'application/x-troff-me',
    'mht':    'message/rfc822',
    'mhtml':  'message/rfc822',
    'mid':    'audio/mid',
    'mny':    'application/x-msmoney',
    'mov':    'video/quicktime',
    'movie':  'video/x-sgi-movie',
    'mp2':    'video/mpeg',
    'mp3':    'audio/mpeg',
    'mpa':    'video/mpeg',
    'mpe':    'video/mpeg',
    'mpeg':   'video/mpeg',
    'mpg':    'video/mpeg',
    'mpp':    'application/vnd.ms-project',
    'mpv2':   'video/mpeg',
    'ms':     'application/x-troff-ms',
    'mvb':    'application/x-msmediaview',
    'nws':    'message/rfc822',
    'oda':    'application/oda',
    'p10':    'application/pkcs10',
    'p12':    'application/x-pkcs12',
    'p7b':    'application/x-pkcs7-certificates',
    'p7c':    'application/x-pkcs7-mime',
    'p7m':    'application/x-pkcs7-mime',
    'p7r':    'application/x-pkcs7-certreqresp',
    'p7s':    'application/x-pkcs7-signature',
    'pbm':    'image/x-portable-bitmap',
    'pdf':    'application/pdf',
    'pfx':    'application/x-pkcs12',
    'pgm':    'image/x-portable-graymap',
    'pko':    'application/ynd.ms-pkipko',
    'pma':    'application/x-perfmon',
    'pmc':    'application/x-perfmon',
    'pml':    'application/x-perfmon',
    'pmr':    'application/x-perfmon',
    'pmw':    'application/x-perfmon',
    'pnm':    'image/x-portable-anymap',
    'pot,':   'application/vnd.ms-powerpoint',
    'ppm':    'image/x-portable-pixmap',
    'pps':    'application/vnd.ms-powerpoint',
    'ppt':    'application/vnd.ms-powerpoint',
    'prf':    'application/pics-rules',
    'ps':     'application/postscript',
    'pub':    'application/x-mspublisher',
    'qt':     'video/quicktime',
    'ra':     'audio/x-pn-realaudio',
    'ram':    'audio/x-pn-realaudio',
    'ras':    'image/x-cmu-raster',
    'rgb':    'image/x-rgb',
    'rmi':    'audio/mid',
    'roff':   'application/x-troff',
    'rtf':    'application/rtf',
    'rtx':    'text/richtext',
    'scd':    'application/x-msschedule',
    'sct':    'text/scriptlet',
    'setpay': 'application/set-payment-initiation',
    'setreg': 'application/set-registration-initiation',
    'sh':     'application/x-sh',
    'shar':   'application/x-shar',
    'sit':    'application/x-stuffit',
    'snd':    'audio/basic',
    'spc':    'application/x-pkcs7-certificates',
    'spl':    'application/futuresplash',
    'src':    'application/x-wais-source',
    'sst':    'application/vnd.ms-pkicertstore',
    'stl':    'application/vnd.ms-pkistl',
    'stm':    'text/html',
    'svg':    'image/svg+xml',
    'sv4cpio':    'application/x-sv4cpio',
    'sv4crc': 'application/x-sv4crc',
    'swf':    'application/x-shockwave-flash',
    't':      'application/x-troff',
    'tar':    'application/x-tar',
    'tcl':    'application/x-tcl',
    'tex':    'application/x-tex',
    'texi':   'application/x-texinfo',
    'texinfo':    'application/x-texinfo',
    'tgz':    'application/x-compressed',
    'tif':    'image/tiff',
    'tiff':   'image/tiff',
    'tr':     'application/x-troff',
    'trm':    'application/x-msterminal',
    'tsv':    'text/tab-separated-values',
    'txt':    'text/plain',
    'uls':    'text/iuls',
    'ustar':  'application/x-ustar',
    'vcf':    'text/x-vcard',
    'vrml':   'x-world/x-vrml',
    'wav':    'audio/x-wav',
    'wcm':    'application/vnd.ms-works',
    'wdb':    'application/vnd.ms-works',
    'wks':    'application/vnd.ms-works',
    'wmf':    'application/x-msmetafile',
    'wps':    'application/vnd.ms-works',
    'wri':    'application/x-mswrite',
    'wrl':    'x-world/x-vrml',
    'wrz':    'x-world/x-vrml',
    'xaf':    'x-world/x-vrml',
    'xbm':    'image/x-xbitmap',
    'xla':    'application/vnd.ms-excel',
    'xlc':    'application/vnd.ms-excel',
    'xlm':    'application/vnd.ms-excel',
    'xls':    'application/vnd.ms-excel',
    'xlt':    'application/vnd.ms-excel',
    'xlw':    'application/vnd.ms-excel',
    'xof':    'x-world/x-vrml',
    'xpm':    'image/x-xpixmap',
    'xwd':    'image/x-xwindowdump',
    'z':      'application/x-compress',
    'zip':    'application/zip'
  }

/**
 * Encrypt chunk using sm4, and sign the encrypted data using sm2
 * @param  chunk message buffer to be encrypted
 * @param  sm4key sm4 key for encryption
 * @param  sm2privateKey sm2 key for signing
 */
function EncryptData(chunk,sm4key,sm2privateKey){
    return new Promise(function(resolve, reject) {
        var msg=[];
        var lengthofseg=chunk.length;
            num = chunk.length % 16;
            var _encryptData=[];
            if(num===0){
                _encryptData = sm4.encrypt(chunk,sm4key);
            }
            else{
                msg.length=0;
                for(var i=0;i<chunk.length;i++){
                    msg[i]=chunk[i];
                }
                for(var i=num;i<16;i++){
                    msg.push(0x00);
                }
                _encryptData=sm4.encrypt(msg,sm4key);
            }
            segsign=sm2.doSignature(chunk, sm2privateKey,{hash:true});
            //seghash=sm3(chunk.toString());
            encryptedsegsize=_encryptData.length;
            info={
                'segment':{
                    //'hash' : seghash,
                    'SegSign':segsign,
                    'SegmentSize' : lengthofseg,
                    'EncryptedSegSize' : encryptedsegsize},
                'encryptdata':_encryptData,
                };
        resolve(info);
    });
}


/**
 * Encrypt the input file with sm4, and generate relevant information
 * @param  infile input filepath
 * @param  outfile output filepath, './0.payload'
 * @param  sm4key key of sm4 ;should be an arry of Hex
 * @param  sm2privateKey privatekey for signing
 */
function encryptfile(infile, outfile, sm4key, sm2privateKey){
    return new Promise(function(resolve, reject) {
        let rs=fs.createReadStream(infile,{highWaterMark:1048576,flag:'binary'});
        var numofseg=0;
        let segment=[];
        var information=[];
        rs.on('data',function (chunk) {  //chunk是buffer类型
            EncryptData(chunk,sm4key,sm2privateKey).then((value) =>{
                segment[numofseg]=value['segment'];
                _encryptData=value['encryptdata'];
                //console.log(segment[numofseg]);
                numofseg++;
                var writebuf =  Buffer.alloc(_encryptData.length);
                for (var i = 0;i < _encryptData.length;i++) {
                    writebuf[i] = _encryptData[i];
                }
                fs.writeFile(outfile, writebuf, {flag:'a+'},  function(err) {
                    if (err) {
                        reject(err);
                    }
                });
            });
        });
        rs.on('end',function () {
            promise = new Promise(function(resolve, reject) {
                var ext=infile.split('.').pop();
                var fileName=infile.split('/').pop().split('.')[0];
                _mimetype=mimeTypes[ext]||'application/octet-stream';
                information={
                    'Payload':{
                        "filePath": '/0.payload',
                        'fileName':fileName,
                        'mimeType':_mimetype,
                        'ext':ext,
                        'isEncrypted':true
                    },
                    'EncryptionInformation':{
                        'SegmentNumber':numofseg,
                        'Segment':segment,
                        'EncryptAlg':'sm4',
                        'SignAlg':'sm2',
                        "SegmentSizeDefault": 1048576,
                        "EncryptedSegmentSizeDefault": 1048576,
                    }
                }
                resolve(information);
            });
            promise.then((value)=>{resolve(value);});
        });
        rs.on('error',function (err) {
            reject(err);
        });
        
    });
}

/**
 * GenerateCapsule, create a zip file containing the payload(encrypted into 0.payload) and the information(info.JSON)
 * @param infile Input filepath
 * @param sm4key Key of sm4 ;should be an arry of Hex
 * @param sm2privateKey Privatekey for signing
 * @param sessionid 
 * @param rules Additional rules set by uer
 */
function GenerateCapsule(infile,sm4key,sm2privateKey,sessionid,rules){
    return new Promise(function(resolve, reject){
        var path=__dirname+'/capsule/'+sessionid;
        var dest=__dirname+'/capsule/'+sessionid+'.zip'
        fs.mkdir(path,function(err){
            if (err) {
                reject(err);
            }
        });
        var _tmppayload=path+'/0.payload';
        var _tmpjsonfile=path+'/info.json';
        encryptfile(infile,_tmppayload,sm4key,sm2privateKey).then((value) => {
            info=value;
            info['KeyAccess']={'SessionId':sessionid};
            if(rules){
                info['Rule']={
                    'AdditionalRules':true,
                    'Rules':rules
                };
            }
            else{
                info['Rule']={
                    'AdditionalRules':false
                };
            }
            fs.writeFile(_tmpjsonfile, JSON.stringify(info), {flag:'w+'},  function(err) {
                if (err) {
                    reject(err);
                }
            });
            compressing.zip.compressDir(path, dest);
            resolve(dest);
        },
        function(error){reject(error);});
    });
}

module.exports = GenerateCapsule;

infile='C:/Users/yangfs/Desktop/Mich-moonlight.mp3'
sm2publicKey='0478eb66fe8fbdc2959a661adb50101be2719132e48c608a2daff4698e6adfc9343075cf679a88f355384207fd2024abd74e1bca73b9b6e6f7cae58132d6addb77';
sm2privateKey='3368d42d859c035bd46959b83ce05466594ae6681b157d7c5d17c2d61a00a157';
sm4key=[0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10];
rules=[{'id':1,
        'parameters':{
            'begintime':1587546760601,
            'endtime': 1588059500000 
        }},
        {'id':2,
        'parameters':{
           'ipaddr':'127.0.0.1' 
        }},
        {'id':3,
        'parameters':{
            'os':'windows',
            'version':'10'
        }}];
GenerateCapsule(infile,sm4key,sm2privateKey,123,rules);